﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Agatha.Common;
using Agatha.Common.InversionOfControl;
using Castle.Core;
using Castle.MicroKernel.Registration;
using Castle.Windsor;

namespace Source.Castle
{
    public class Container : ICastleContainer
    {
        private readonly IWindsorContainer windsorContainer;

        public Container() : this(new WindsorContainer()) { }

        public Container(IWindsorContainer windsorContainer)
        {
            this.windsorContainer = windsorContainer;
        }

        public void Register(Type componentType, Type implementationType, Lifestyle lifeStyle)
        {
            var registration = Component.For(componentType).ImplementedBy(implementationType);
            windsorContainer.Register(AddLifeStyleToRegistration(lifeStyle, registration));
        }

        public void Register(Type componentType, Lifestyle lifeStyle)
        {
            var registration = Component.For(componentType);
            windsorContainer.Register(AddLifeStyleToRegistration(lifeStyle, registration));
        }

        public void Register(Type componentType, Assembly assembly)
        {
            windsorContainer.Register(AllTypes.Of(componentType).FromAssembly(assembly)
              .Configure(c => c.LifeStyle.Is(LifestyleType.Transient)));
        }

        public void Register<TComponent, TImplementation>(Lifestyle lifestyle) where TImplementation : TComponent
        {
            Register(typeof(TComponent), typeof(TImplementation), lifestyle);
        }

        public void RegisterInstance(Type componentType, object instance)
        {
            windsorContainer.Register(Component.For(componentType).Instance(instance));
        }

        public void RegisterInstance<TComponent>(TComponent instance)
        {
            RegisterInstance(typeof(TComponent), instance);
        }

        public TComponent Resolve<TComponent>(object component)
        {
            return windsorContainer.Resolve<TComponent>(component);
        }

        public TComponent Resolve<TComponent>()
        {
            return windsorContainer.Resolve<TComponent>();
        }

        public TComponent Resolve<TComponent>(string key)
        {
            return windsorContainer.Resolve<TComponent>(key);
        }

        public object Resolve(Type componentType)
        {
            return windsorContainer.Resolve(componentType);
        }

        public void Release(object component)
        {
            windsorContainer.Release(component);
        }

        private static ComponentRegistration<TInterface> AddLifeStyleToRegistration<TInterface>(Lifestyle lifestyle, ComponentRegistration<TInterface> registration)
        {
            if (lifestyle == Lifestyle.Singleton)
            {
                registration = registration.LifeStyle.Singleton;
            }
            else if (lifestyle == Lifestyle.Transient)
            {
                registration = registration.LifeStyle.Transient;
            }
            else
            {
                throw new ArgumentOutOfRangeException("lifestyle", "Only Transient and Singleton is supported");
            }

            return registration;
        }
    }
}
